<template>
  <div class="geciBox flex-row-center-center">
    <div class="backgroundImage"/>
    <div class="geciUi">
      <p class="geciUiP">{{ songName }}</p>
      <div ref="geciLyric" class="geciLyric">
        <ul ref="geciUl" class="LyricUl"></ul>
      </div>
      <div class="play">
        <div class="playBackgroundImg-box">
          <img
            class="playBackgroundImg"
            src="../../image/monster.png"
            alt=""
            srcset=""
          />
        </div>
        <div class="rightplay">
          <audio :autoplay="autoplay" ref="audio" class="audio" :src="musicPath"></audio>
          <div class="progress-box">
            <el-slider
              class="progress-bar"
              v-model="progressValue"
              :min="0"
              :max="100"
              :show-tooltip="false"
              @change="alterProgress"
            ></el-slider>
            <span class="passTime">{{ currentTime }}</span>
            /
            <span class="totalTime">{{ audioTimer }}</span>
          </div>
          <div class="control-panel">
            <!-- 上一首 -->
            <div @click="endedNext('-')" class="previous previousTrack">
              <svg-icon class="svg-icon" name="previousTrack" />
            </div>
            <!-- 播放暂停 -->
            <div @click="playAudio" class="previous playAudio"></div>
            <!-- 下一首 -->
            <div @click="endedNext('+')" class="previous nextSong">
              <svg-icon name="nextSong" />
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="songFrequency">
      <canvas class="canvas" ref="canvas"></canvas>
    </div>
    <shade
      :songlist="mp3List"
      :songIndex = "songIndex"
      @editAutoPlay="editAutoPlay" 
      @searchMusic="getMusicList"
      @geturl="geturl"
      @setRandomBackground="setRandomBackground"
      @randomGetUrl="randomGetUrl"
      @getMP3List="getMusicList"
    />
  </div>
</template>

<script>

import lyric from "./lyrics/lyric";
import { getMusic, list } from "@/api/music/index"
import notify from "@/unit/error";
import { getCutlyrics, initLrcUlText} from "../../unit/music_public_fn/index"
import { mathBarkroundPath, randomColor } from "../../unit/music_public_fn/random"
import { mapState, mapMutations} from "vuex"

import shade from "@/components/shade/shade.vue";

export default {
  name: "geci",
  components:{ shade },
  data() {
    return {
      lrc: [],
      songName: "",     // 歌曲名字
      lyricList: [],    // 歌词数组
      lyricObj: {
        audio: null,
        geciLyric: null,
        canvas1: null,
      },
      heightLight: 0,
      liHeight: 0,
      // 是否初始化了音源
      isInit: false,
      analyzerEle: null,
      dataArray: [],
      source: null,
      ctx: null,
      // 音频轨道长度
      len: 0,
      barWidth: 0,
      // 画布
      canvasWidth: 0,
      canvasHeight: 0,
      // 音乐时长
      audioTimer: 0,
      // 已播放长度
      currentTime: "0:00",
      // 是否开始播放
      isAudioPlay: false,
      // 播放的歌曲下标
      songIndex: 0,
      // 是否自动播放
      autoplay: true,
      // 随机播放
      randomPlay: false,
      // 进度条
      progressValue: 0,
      // 歌曲列表
      mp3List: [],
      lrcList: [],
      // musicPath: '' || require("../../assets/video/qifenle.mp3"),
      musicPath: '',
      randomColorList: [],
    };
  },
  watch:{
    isAudioPlay(newV){
      this.setPlayAudioClass()
    }
  },
  mounted() {
    // this.lyricList = lyric;
    // 获取音乐列表
    this.getMusicList()
    // 获取元素/监听事件
    this.addEventList();
    // this.setCutlyrics();  // √
    // this.createlrcElements();    // √
    this.initCanvas();
    this.draw();
    // 获取歌曲时长
    this.loadeddata();
    // 随机播放
    // this.getRandomUrl();
    // 设置随机背景
    this.setRandomBackground();  // √
    // 设置随机颜色
    this.mathcolor();  // √
  },

  methods: {
    // 获取音乐列表
    getMusicList(e){
      let data = null
      if(e){
        data = {
          value: e
        }
      }
      list(data).then(res => {
        this.mp3List = res
      })
    },
    // 获取歌曲Base64数据
    geturl(e) {
      if(e == undefined){
        return ''
      }
      // 保存index的值作为当前播放的位置
      if(e.index){
        this.songIndex = e.index
      }
      let data = {
        _id: e._id
      }
      this.musicPath = null;
      getMusic(data).then(async res => {
        this.musicPath = "data:audio/wav;base64," + res.base64
        this.songName = res.music_name
        if(res.music_lrc){
          this.lrc = res.music_lrc.text
          // 处理歌词
          await this.lrcTextTranArray()
        }else{
          this.$refs.geciUl.innerHTML = ''
        }
        // 是否为自动播放
        if(this.autoplay){
          this.isAudioPlay = true
        }else{
          this.isAudioPlay = false
        }
        notify('success',`正在播放：${this.songName}`);
      })
      this.setRandomBackground();
      this.mathcolor();
    },
    // 监听事件
    addEventList() {
      this.lyricObj.audio = this.$refs.audio;
      this.lyricObj.geciLyric = this.$refs.geciLyric;
      this.lyricObj.canvas1 = this.$refs.canvas;
      this.lyricObj.audio.addEventListener("timeupdate", this.offsetFn);
      this.lyricObj.audio.addEventListener("play", this.playFn);
      this.lyricObj.audio.addEventListener("loadeddata", this.loadeddata);
      this.lyricObj.audio.addEventListener("ended", this.endedNext);
    },
    // 播放/暂停音乐
    playAudio() {
      this.isAudioPlay = !this.isAudioPlay
    },
    // 
    setPlayAudioClass(){
      let el = document.getElementsByClassName("playAudio")[0];
      if(this.isAudioPlay){
        el.classList.add("playing");
        this.lyricObj.audio.play();
      }else{
        this.lyricObj.audio.pause();
        el.classList.remove("playing");
      }
    },
    // 随机播放
    randomGetUrl(){
      this.randomPlay = true
    },
    getRandomUrl(){
      this.songIndex = (Math.floor(Math.random()* this.mp3List.length))
      let data = {
        _id: this.mp3List[this.songIndex]['_id']
      }
      this.geturl(data);
    },
    // 切换歌曲
    endedNext(type) {
      // 如果为随机播放
      if(this.randomPlay){
        this.getRandomUrl();
        return;
      }
      // 如果点击了上/下
      if(type == '-'){
        if(this.songIndex == 0) {
          this.songIndex = 0
        }
        
        if(this.songIndex > 0){
          this.songIndex--;
        }
      }else{
        if(this.songIndex + 1 == this.mp3List.length){
          notify('error', '已经是最后一首歌啦');
          return;
        }
        this.songIndex++;
      }
      let data = {
        _id: this.mp3List[this.songIndex]['_id']
      }
      
      this.geturl(data);
    },
    // 获取歌曲时长
    loadeddata(e) {
      if (e !== undefined) {
        let time = e.target.duration.toFixed(2);
        let minute = (time / 60).toString().split(".")[0];
        let second = (time - minute * 60).toFixed(0);
        let mp3Length = `${minute}:${second}`;
        this.audioTimer = mp3Length;
      }
    },
    // 处理歌词文本
    async lrcTextTranArray(){
      let str = this.lrc.split("\n")
      for(let i =0; i<str.length; i++){
        str[i] = str[i].replace(/(^\s*)|(\s*$)/g, ""); //去除前后空格
      }
      this.lyricList = str;
      // 删除歌词列表
      this.$refs.geciUl.innerHTML = ''
      // 重置高亮下标
      this.heightLight = 0;
      // 调用处理歌词方法
      await this.setCutlyrics();
      // 重新渲染歌词
      await this.createlrcElements();
    },
    // 格式化歌词（√）
    async setCutlyrics() {
      this.lyricList = getCutlyrics(this.lyricList);
      this.lyricList.sort((a, b)=>{
        return a.timer -  b.timer
      })
    },
    // 创建歌词元素（√）
    async createlrcElements() {
      if(!this.lyricList) return;
      let textLi = null;
      try {
        textLi = initLrcUlText(this.lyricList, 'lyricLi');
      } catch (error) {
        console.log(error)
      }
      let el = this.$refs.geciUl
      el.style.transform = 'translateY(0px)';
      await el.appendChild(textLi);
    },
    // 计算以播时间
    getCurrentTime(e) {
      let time = e.target.currentTime.toString();
      let splitTime = Math.floor(time.split(".")[0]);
      this.progressValue = Math.floor(
        (e.target.currentTime / e.target.duration) * 100
      );
      if (splitTime < 60) {
        this.currentTime =
          splitTime < 10 ? "0:0" + splitTime : "0:" + splitTime;
      } else {
        let minute = (splitTime / 60).toString().split(".")[0];
        let second =
          splitTime % 60 < 10 ? "0" + (splitTime % 60) : splitTime % 60;
        this.currentTime = `${minute}:${second}`;
      }
    },
    // 计算高亮下标
    setheightLight() {
      const timer = this.lyricObj.audio.currentTime;
      let el = this.$refs.geciUl
      for (let i = 0; i < this.lyricList.length; i++) {
        if (timer < this.lyricList[i].timer) {
          if (this.heightLight == 0) break;
          this.heightLight = i - 1;
          break;
        }else{
          this.heightLight = i - 1;
        }

        for(let j = 0; j < i; j++){
          if (el.children[j].classList.contains("active")) {
            el.children[j].classList.remove(
              "active"
            );
          }
        }
      }
      try {
        const li = this.$refs.geciUl.children[this.heightLight];
        li.classList.add("active");
      } catch (error) {
        console.log(error)
      }
      this.setRollDistance();
    },
    // 计算滚动距离
    setRollDistance() {
      // 将元素本身的高度给到滚动距离
      this.liHeight = this.$refs.geciUl.childNodes[this.heightLight].offsetHeight;

      const geciUl = this.lyricObj.geciLyric;
      let offsetHeight =
        this.heightLight * this.liHeight -
        geciUl["clientHeight"] / 2 +
        this.liHeight * 2;
      if (offsetHeight < 0) {
        offsetHeight = 0;
      }
      this.$refs.geciUl.style.transform = `translateY(-${offsetHeight}px)`;
    },
    // 关联歌词滚动，判断是否高亮，计算以播时长
    offsetFn(e) {
      this.getCurrentTime(e);
      if(this.heightLight < this.lyricList.length && this.lyricList.length > 1){
        this.setheightLight();
      }
    },

    // 初始化画布
    initCanvas() {
      let can = this.$refs.canvas;
      let el = document.getElementsByClassName('songFrequency')[0];
      this.canvasWidth = parseInt(window.getComputedStyle(el).width);
      this.canvasHeight = parseInt(window.getComputedStyle(el).height) - 50;
      can.width = this.canvasWidth;
      can.height = this.canvasHeight;
      this.ctx = can.getContext("2d");
    },
    // 解析音乐频谱
    playFn() {
      if (this.isInit) return;
      // 初始化
      // 创建一个音频上下文
      let audCtx = new AudioContext();
      // 创建一个音频源节点
      let audioEle = audCtx.createMediaElementSource(this.$refs.audio);
      // 创建一个分析器节点
      this.analyzerEle = audCtx.createAnalyser();
      this.analyzerEle.fftSize = 512;
      // 创建一个数组，用于接收分析器节点，分析数组
      this.dataArray = new Uint8Array(this.analyzerEle.frequencyBinCount);
      audioEle.connect(this.analyzerEle);
      this.analyzerEle.connect(audCtx.destination);
      this.isInit = true;
    },
    // 画布
    draw() {
      requestAnimationFrame(this.draw);
      if (!this.isInit) {
        return;
      }
      // 清空画布
      this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
      this.analyzerEle.getByteFrequencyData(this.dataArray);
      this.len = this.dataArray.length / 2;
      this.barWidth = this.canvasWidth / this.len;

      // Create gradient
      let grd = this.ctx.createLinearGradient(
        0,
        0,
        this.canvasWidth,
        this.canvasHeight
      );

      grd.addColorStop(0, this.randomColorList[0]);
      grd.addColorStop(1, this.randomColorList[1]);

      // grd.addColorStop(0,"#00ffff");
      // grd.addColorStop(1,"#1fabed");
      // grd.addColorStop(2,"#0000ff");
      // grd.addColorStop(3,"#6e2ce8");
      // grd.addColorStop(4,"#8e45e8");
      // grd.addColorStop(5,"#caf245");

      // Fill with gradient
      this.ctx.fillStyle = grd;
      // this.ctx.fillStyle="#ffd04b";

      for (let i = 0; i < this.len; i++) {
        let data = this.dataArray[i];
        let barHeight = (data / 255) * this.canvasHeight - 30;
        let x = i * this.barWidth;
        // let x2 = 300/2 - (i+1)*barWidth;
        let y = this.canvasHeight - barHeight;
        try {
          this.ctx.fillRect(x, y, this.barWidth - 4, barHeight);
        } catch (error) {
          console.log(error);
        }
      }
    },
    // 修改自动播放值
    editAutoPlay(){
      this.autoplay = !this.autoplay
    },
    // 进度条改变时触发
    alterProgress() {
      // console.log(this.progressValue)
    },
    // 设置随机颜色（√）
    mathcolor(){
      try {
        this.randomColorList = randomColor(2)
      } catch (error) {
        console.log(error)
      }
    },
    // 设置随机背景（√）
    async setRandomBackground(){
      await mathBarkroundPath('backgroundImage')
    },
  },
};
</script>

<style lang="scss">
@import './css/scrollbar.scss';

:root {
  --textHeight: 60px;
  --audio: 30px;
}

.geciBox {
  height: 100%;
  position: relative;
  overflow: hidden;
  user-select: none;
}

.geciUiP {
  margin: 0px;
  padding: 0px;
  height: var(--textHeight);
  line-height: var(--textHeight);
  font-size: 28px;
  color: #fff;
}
.geciUi {
  height: 100%;
  width: 50%;
  color: #666;
  text-align: center;
  overflow: hidden;
  position: relative;
  background: rgba($color: #000000, $alpha: 0.1);

  .geciLyric {
    height: calc(100% - var(--textHeight) - var(--audio) - 50px);
    overflow: hidden;
    .LyricUl {
      .lyricLi {
        text-decoration: none;
        // height: 60px;
        // line-height: 60px;
        padding: 15px 0px;
        transition: 0.3s;
        font-size: 24px;
        &.active {
          color: #fff;
          text-decoration: underline;
          filter: drop-shadow(0px 0px 2px #fff);
          transform: scale(1.3);
        }
      }
      .liheight{
        padding: 15px 0px;
      }
    }
  }

  .play {
    width: 100%;
    height: 80px;
    background: rgba($color: #000000, $alpha: 0.2);
    display: flex;
    .playBackgroundImg-box {
      height: inherit;
      width: 80px;
      img {
        height: inherit;
      }
    }
    .rightplay {
      width: 100%;
      .progress-box {
        color: #fff;
        font-size: 18px;
        height: 30px;
        width: inherit;
        display: flex;
        align-items: center;
        justify-content: space-around;

        .progress-bar {
          display: block;
          width: 80%;
          height: 6px;
          border-radius: 3px;
          margin: 0px;
          z-index: 0;
          .el-slider__runway {
            margin: 0px;
            background-color: transparent;
            .el-slider__bar{
              background-color: transparent;
            }
            .el-slider__button-wrapper{
              background: url('@/assets/image/fire.png');
              transition: all 1s;
              .el-tooltip.el-slider__button{
                width: 20px;
                height: 20px;
                background: url('@/assets/image/fire.png');
                border: none;
                background-size: 100% 100%;
              }
            }
          }
        }
      }
      .control-panel {
        $height: 35px;
        height: 50px;
        width: inherit;
        display: flex;
        justify-content: space-evenly;
        .previous {
          width: $height;
          height: $height;
          cursor: pointer;
          .svg-icon {
            width: $height !important;
            height: $height !important;
            color: #fff;
          }
        }
        .playAudio {
          width: $height;
          height: $height;
          background-color: rgba($color: #fff, $alpha: 0.7);
          border-radius: 0%;
          transition: all 0.3s;
        }
        .playing {
          border-radius: 50%;
        }
      }
    }
  }
  .audio {
    width: 280px;
    height: var(--audio);
    position: absolute;
    left: 50%;
    bottom: 10px;
    transform: translate(-50%);
    // background: rgba($color: #000000, $alpha: .4);
  }
}

.songFrequency {
  height: 100%;
  width: 50%;
  z-index: 2;
}

.backgroundImage{
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0px;
  left: 0px;
  z-index: -1;
  background-size: 0% auto;
  background-repeat: no-repeat;
  background-position-y: -100px;
  filter: blur(8px);
  // 背景过渡
  transition: all .4s;
  &{
    background-size: 100% auto;
  }
}
</style>
